#include "PakFile.h"
#include "ComponentManager.h"
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
#  include <fcntl.h>
#  include <io.h>
#  define SET_BINARY_MODE(file) _setmode(_fileno(file), O_BINARY)
#else
#  define SET_BINARY_MODE(file)
#endif

#include <zlib.h>
CPakFile::CPakFile(void):m_numberOfFile(0), m_buffer(0)//m_file(0)
{
}

CPakFile::~CPakFile(void)
{
	if(m_buffer !=0)
	{
		delete m_buffer;
		m_buffer = 0;
	}
}

bool CPakFile::loadFile(const string& filename)
{
	m_filename = filename;

	//open the stream
	FILE* m_file;
#ifdef _WIN
	if(fopen_s(&m_file, filename.c_str(), "rb") !=0)
		return false;
#endif

#ifdef _GP2X
	m_file = fopen(filename.c_str(), "r");
	if(m_file == 0)
	{
		CM.LOGCONSOLE().Log()<<"Can't open the file : "<<filename.c_str()<<"\n";
		return false;
	}
#endif
	SET_BINARY_MODE(m_file)
	

	//unzip the file
	if(!unzip(m_file))
	{
		CM.LOGCONSOLE().Log()<<"Can't unzip the file\n";
		return false;
	}

	//close the file
	fclose(m_file);

	//get the files
	makeListOfFile();
	return true;
}

bool CPakFile::closeFile(void)
{
	if(m_buffer !=0)
	{
		delete m_buffer;
		m_buffer = 0;
	}
	return true;
}

bool CPakFile::getFile(const string& filename, char** buffer, int* size)const
{
	//look for the file
	bool found = false;
	int i = 0;
	while(!found && i<m_numberOfFile)
	{
		if(m_dataFileArray[i].m_filename.compare(filename)== 0)
			found = true;
		else
			i++;
	}
	if(!found)
		return false;

	//get the size
	*size = m_dataFileArray[i].m_size;
	int offset = m_dataFileArray[i].m_offset;
	*buffer = m_buffer + offset;

	return true;


}

bool CPakFile::unzip(FILE* file)
{
	//get the size of the file unzipped
	fseek(file, 0, SEEK_SET);
	long sizeUnzipped = 0;
	fread(&sizeUnzipped, sizeof(long), 1, file);

	//create the temporary buffer
	m_buffer = new char[sizeUnzipped];

	int have;
	z_stream strm;
	const int CHUNK = 262144; //256k
	unsigned char in[CHUNK];
	unsigned char out[CHUNK];

	//initialise strm
	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;
	strm.avail_in = 0;
	strm.next_in = Z_NULL;

	int result = inflateInit(&strm);
	if(result != Z_OK)
		exit(1);

	int offsetCpy = 0;
	//decompress
	do
	{
		strm.avail_in = fread(in, 1, CHUNK, file);
		if(ferror(file))
		{
			inflateEnd(&strm);
			return false;
		}

		if(strm.avail_in == 0)
			break;

		strm.next_in = in;

		//inflate
		do
		{
			strm.avail_out = CHUNK;
			strm.next_out = out;

			result = inflate(&strm, Z_NO_FLUSH);
			switch(result)
			{
			case Z_NEED_DICT:
				result = Z_DATA_ERROR;
			case Z_DATA_ERROR:
			case Z_MEM_ERROR:
				inflateEnd(&strm);
				return false;
			}

			//copy the uncompressed data in the buffer
			have = CHUNK - strm.avail_out;
			if(offsetCpy+have>sizeUnzipped)
				return false;
			memcpy(m_buffer+offsetCpy, out, have);
			offsetCpy+=have;
			
		}while(strm.avail_out == 0);
	}while(result != Z_STREAM_END);

	inflateEnd(&strm);


	return true;
}

bool CPakFile::makeListOfFile()
{
	int offsetBuffer = 0;
	int sizeOfInt = sizeof(int);
	int sizeOfLong = sizeof(long long);
	//get the number of file
	memcpy(&m_numberOfFile, m_buffer, sizeOfInt);
	offsetBuffer += sizeOfInt;

	//for every file
	for(int i=0; i<m_numberOfFile; i++)
	{
		//create a new datafile
		dataFile d;

		//get the name
		char fileName[255];
		memcpy(fileName, m_buffer+offsetBuffer, 255);
		d.m_filename=fileName;
		offsetBuffer+= 255;

		//get the size
		long long size;
		memcpy(&size, m_buffer+offsetBuffer, sizeOfLong);
		offsetBuffer+=sizeOfLong;
		d.m_size= (int)size;

		//get the offset
		long long offset;
		memcpy(&offset, m_buffer+offsetBuffer, sizeOfLong);
		offsetBuffer+=sizeOfLong;
		d.m_offset = (int)offset;

		m_dataFileArray.push_back(d);

	}
	return true;
}
